package com.ruoyi.iot.service.task;

import com.ruoyi.iot.domain.FacTaskjob;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author
 * @Date 2021/9/17 16:36
 */

public abstract class BaseTaskService {
//    /**
//     * 系统名称
//     */
//    @Value("${spring.application.name}")
//    protected String servername;
    /**
     * 可重入锁
     */
    private ReentrantLock lock = new ReentrantLock();
    /**
     * 定时任务线程池
     */
    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;

    /**
     * 存放已经启动的任务map
     */
    private Map<String, ScheduledFuture> scheduledFutureMap = new ConcurrentHashMap<>();

    /**
     * 查询任务
     * @param taskKey
     * @return
     */
    public abstract FacTaskjob getTaskBykey(String taskKey);

    /**
     * 查询所有的任务
     * @return
     */
    public abstract List<FacTaskjob> getAllTask();

    /**
     * 查询所有需要运行的任务
      * @return
     */
    public abstract List<FacTaskjob> getAllNeedStartTask();

    /**
     * 所有任务列表
     */
    public List<FacTaskjob> taskList() {
        //数据库查询所有任务 => 未做分页
        List<FacTaskjob> taskBeanList = getAllTask();
        if (CollectionUtils.isEmpty(taskBeanList)) {
            return new ArrayList<>();
        }

        for (FacTaskjob taskBean : taskBeanList) {
            String taskKey = taskBean.getTaskkey();
            //是否启动标记处理
            taskBean.setStartFlag(this.isStart(taskKey));
        }
        return taskBeanList;
    }

    /**
     * 所有任务列表
     */
    public List<FacTaskjob> startedTaskList() {
        //数据库查询所有任务 => 未做分页
        List<FacTaskjob> taskBeanList = getAllTask();
        List<FacTaskjob> satrttaskList = new ArrayList<>();
        if (CollectionUtils.isEmpty(taskBeanList)) {
            return new ArrayList<>();
        }

        for (FacTaskjob taskBean : taskBeanList) {
            String taskKey = taskBean.getTaskkey();
            if(this.isStart(taskKey)){
                //是否启动标记处理
                taskBean.setStartFlag(true);
                satrttaskList.add(taskBean);
            }
        }
        return satrttaskList;
    }

    /**
     * 根据任务key 启动任务
     */
    public Boolean start(String taskKey){
        //添加锁放一个线程启动，防止多人启动多次
        lock.lock();
        try {
            //校验是否已经启动
            if (this.isStart(taskKey)) {
                return false;
            }
            //根据key数据库获取任务配置信息
            FacTaskjob scheduledTask = getTaskBykey(taskKey);
            //不存在任务
            if (scheduledTask==null){
                return false;
            }
            try{
                Class t=Class.forName(scheduledTask.getTaskclass());
            }catch (Exception e){
                return false;
            }
            //启动任务
            this.doStartTask(scheduledTask);
        } finally {
            // 释放锁
            lock.unlock();
        }
        return true;
    }

    /**
     * 根据 key 停止任务
     */
    public Boolean stop(String taskKey) {
        //当前任务实例是否存在
        boolean taskStartFlag = scheduledFutureMap.containsKey(taskKey);
        if (taskStartFlag) {
            //获取任务实例
            ScheduledFuture scheduledFuture = scheduledFutureMap.get(taskKey);
            //关闭实例
            scheduledFuture.cancel(true);
        }
        return taskStartFlag;
    }

    /**
     * 根据任务key 重启任务
     */
    public Boolean restart(String taskKey) {
        //先停止
        this.stop(taskKey);
        //再启动
        return this.start(taskKey);
    }

    /**
     * 程序启动时初始化 ==> 启动所有正常状态的任务
     */
    public void initAllTask(List<FacTaskjob> scheduledTaskList) {

        if (CollectionUtils.isEmpty(scheduledTaskList)) {
            return;
        }
        for (FacTaskjob scheduledTask : scheduledTaskList) {
            //任务 key
            String taskKey = scheduledTask.getTaskkey();
            //校验是否已经启动
            if (this.isStart(taskKey)) {
                continue;
            }
            //启动任务
            this.doStartTask(scheduledTask);
        }
    }

    /**
     * 执行启动任务
     */
    @SneakyThrows
    private void doStartTask(FacTaskjob scheduledTask) {
        //任务key
        String taskKey = scheduledTask.getTaskkey();
        //定时表达式
        final String taskCron = scheduledTask.getTaskcron();
        //获取需要定时调度的接口
        Class t= (Class) Class.forName(scheduledTask.getTaskclass());
        TaskJob scheduledTaskJob = (TaskJob)t.newInstance() ;
        ScheduledFuture scheduledFuture = threadPoolTaskScheduler.schedule(scheduledTaskJob,
                new Trigger() {
                    @Override
                    public Date nextExecutionTime(TriggerContext triggerContext) {
                        CronTrigger cronTrigger = new CronTrigger(taskCron);
                        return cronTrigger.nextExecutionTime(triggerContext);
                    }
//                    @Override
//                    public Instant nextExecution(TriggerContext triggerContext) {
//                        CronTrigger cronTrigger = new CronTrigger(taskCron);
//                        return cronTrigger.nextExecution(triggerContext);
////                        return null;
//                    }
                });
        //将启动的任务放入 map
        scheduledFutureMap.put(taskKey, scheduledFuture);
    }

    /**
     * 任务是否已经启动
     */
    private boolean isStart(String taskKey) {
        //校验是否已经启动
        if (scheduledFutureMap.containsKey(taskKey)) {
            if (!scheduledFutureMap.get(taskKey).isCancelled()) {
                return true;
            }
        }
        return false;
    }
}
